ServerEvents.commandRegistry(event => {
    const { commands: Commands, arguments: Arguments } = event;
    event.register(Commands.literal('party')
        .then(Commands.literal('invite')
            .then(Commands.argument('player', Arguments.PLAYER.create(event))
                .executes(ctx => {
                    return global.partyInvitePlayer(ctx, Arguments)
                })
            )
        )
        .then(Commands.literal('leave')
            .executes(ctx => {
                return global.partyLeave(ctx, Arguments)
            })
        )
        .then(Commands.literal('accept')
            .then(Commands.argument('player', Arguments.PLAYER.create(event))
                .executes(ctx => {
                    return global.partyAcceptPlayer(ctx, Arguments)
                })
            )
        )
        .then(Commands.literal('help')
            .executes(ctx => {
                return global.partyHelp(ctx, Arguments)
            })
        )
        .then(Commands.literal('info')
            .executes(ctx => {
                return global.partyInfo(ctx, Arguments)
            })
        )
        .then(Commands.literal('transfer')
            .then(Commands.argument('player', Arguments.PLAYER.create(event))
                .executes(ctx => {
                    return global.partyTransferPlayer(ctx, Arguments)
                })
            )
        )
    )
})


/**
 * @param {Internal.CommandContext_<Internal.CommandSourceStack>} ctx
 * @param {Internal.ArgumentTypeWrapper} Arguments
*/

global.partyInvitePlayer = function (ctx, Arguments) {
    var player = Arguments.PLAYER.getResult(ctx, "player")
    var inviter = ctx.source.playerOrException

    if (inviter.username == player.username) {
        inviter.tell(Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你不能邀请自己!").aqua()]))
        return 1
    }

    if (player.forgePersistentData.contains("isInParty")) {
        inviter.tell(Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("邀请对象已经在一个队伍中了!").aqua()]))
        return 1
    }

    if (UnprocessedPartyInvitation.containsKey(player.username)) {
        var iterator = UnprocessedPartyInvitation.get(player.username).iterator()
        while (iterator.hasNext()) {
            var invitation = iterator.next()
            if (invitation.inviterName == inviter.username && invitation.remainingTime > 0) {
                inviter.tell(Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString(player.username + " 当前拥有一个来自你的未接受邀请!").aqua()]))
                return 1
            }
        }
    }

    if (inviter.username != player.username) {
        inviter.tell(Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你邀请了 " + player.username + " 加入你的队伍,他有60秒的时间接受邀请!").aqua()]))
        player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
        player.tell(Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString(inviter.username + "邀请你加入组队").blue(), Component.ofString(",你有60秒的时间点击 ").blue(), Component.ofString("这里").clickRunCommand("/party accept " + inviter.username).hover(Component.ofString("点我加入组队!")).underlined().aqua(), Component.ofString(" 以加入").blue()]))
        player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
        creatNewParty(inviter)
        addNewPartyInvitation(player, inviter)
    }

    return 1
}


/**
 * @param {Internal.CommandContext_<Internal.CommandSourceStack>} ctx
 * @param {Internal.ArgumentTypeWrapper} Arguments
*/
global.partyLeave = function (ctx, Arguments) {
    var player = ctx.source.playerOrException
    if (player.forgePersistentData.contains("isInParty")) {
        var Party = getPartyByLeaderName(player.forgePersistentData.getString("isInParty"))
        var allMember = Party.getAllMember()
        player.forgePersistentData.remove("isInParty")
        if (Party) {
            allMember.forEach(member => {
                member.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString(player.username + "离开了队伍").aqua()])])

            })
            if (player.username == Party.leader) {
                if (Party.member.size() > 0) {
                    player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("由于你是队长,组队队长已移交至 " + Party.member.get(0)).aqua()])])

                    var newLeader = getPlayerByName(Party.member.get(0))
                    newLeader.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("由于队长离队,组队队长已移交至你").aqua()])])
                    var newParty = creatNewParty(newLeader)
                    Party.member.forEach(name => {
                        if (name != Party.member.get(0)) {
                            var member = getPlayerByName(name)
                            newParty.addNewMember(member)
                            member.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("由于队长离队,组队队长已移交至 " + newLeader.username).aqua()])])
                        }
                    })
                    partyList.remove(Party.leader)
                } else {
                    player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("由于队伍里没有任何玩家,组队已解散").aqua()])])
                    partyList.remove(Party.leader)
                }
            } else {
                Party.removeMember(player)
            }
        }
    } else {
        player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你当前不在一个队伍里!").aqua()])])

        return 0
    }
    return 1
}

/**
 * @param {Internal.CommandContext_<Internal.CommandSourceStack>} ctx
 * @param {Internal.ArgumentTypeWrapper} Arguments
*/
global.partyAcceptPlayer = function (ctx, Arguments) {
    /**@type {Internal.Player}*/
    var inviter = Arguments.PLAYER.getResult(ctx, "player")
    var player = ctx.source.playerOrException
    var party = getPartyByLeaderName(inviter.username)
    if (player.forgePersistentData.contains("isInParty")) {
        player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你已经在一个队伍里了!").aqua()])])
        return 1
    }

    if (player) {
        if (party) {
            if (UnprocessedPartyInvitation.containsKey(player.username)) {
                var iterator = UnprocessedPartyInvitation.get(player.username).iterator()
                while (true) {
                    if (iterator.hasNext()) {
                        var partyInvitation = iterator.next()
                        if (partyInvitation.inviterName == inviter.username) {
                            iterator.remove()
                            party.addNewMember(player)
                            player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("成功加入 " + inviter.username + " 的组队!").aqua()])])
                            inviter.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString(player.username + " 加入了你的队伍!").aqua()])])
                            break
                        }
                    } else {
                        player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("没有来自" + inviter.username + "的组队邀请! (未邀请或邀请超时)").aqua()])])
                        break
                    }
                }
            } else {
                player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("没有来自" + inviter.username + "的组队邀请! (未邀请或邀请超时)").aqua()])])
            }
        } else {
            player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("队伍不存在!").aqua()])])
        }
    }
    return 1
}

global.partyHelp = function (ctx, Arguments) {
    /**@type {Internal.Player}*/
    var player = ctx.source.playerOrException
    player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
    player.tell([Component.join([Component.ofString("/party invite player : ").bold().blue(), Component.ofString("自动创建组队并邀请一位玩家加入你的组队")]).aqua()])
    player.tell([Component.join([Component.ofString("/party leave : ").bold().blue(), Component.ofString("离开当前组队").aqua()])])
    player.tell([Component.join([Component.ofString("/party info : ").bold().blue(), Component.ofString("显示当前队伍信息").aqua()])])
    player.tell([Component.join([Component.ofString("/party transfer player : ").bold().blue(), Component.ofString("将组队移交给队伍中的成员")]).aqua()])
    player.tell([Component.join([Component.ofString("/party accept player : ").bold().blue(), Component.ofString("同意加入某人的组队")]).aqua()])
    player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
    return 1
}
global.partyInfo = function (ctx, Arguments) {
    /**@type {Internal.Player}*/
    var player = ctx.source.playerOrException
    if (player.forgePersistentData.contains("isInParty")) {
        var party = getPartyByLeaderName(player.forgePersistentData.getString("isInParty"))
        player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
        player.tell(Component.ofString("组队信息:").aqua())
        player.tell(Component.ofString("    队长:" + party.leader).aqua())
        player.tell(Component.ofString("    成员:" + party.member).aqua())
        player.tell(Component.ofString("---------------------------------------------------------------").bold().blue())
    } else {
        player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你当前不在一个队伍里!").aqua()])])
    }
    return 1
}


global.partyTransferPlayer = function (ctx, Arguments) {
    /**@type {Internal.Player}*/
    var newLeader = Arguments.PLAYER.getResult(ctx, "player")
    /**@type {Internal.Player}*/
    var oldLeader = ctx.source.playerOrException
    if (oldLeader.forgePersistentData.contains("isInParty")) {
        if (oldLeader.forgePersistentData.getString("isInParty") == oldLeader.username) {
            if (oldLeader != newLeader) {
                if (newLeader.forgePersistentData.contains("isInParty") && newLeader.forgePersistentData.getString("isInParty") == oldLeader.username) {
                    var party = getPartyByLeaderName(oldLeader.username)
                    partyList.remove(oldLeader.username)
                    var newParty = creatNewParty(newLeader)
                    party.getAllMember().forEach(member => {
                        if (member.username != newLeader.username) {
                            newParty.addNewMember(member)
                        }
                    })
                } else {
                    oldLeader.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("转交目标当前不在你的队伍里!").aqua()])])
                }
            } else {
                oldLeader.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你不能把组队移交给自己!").aqua()])])
            }
        } else {
            oldLeader.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你不是当前组队的队长!").aqua()])])
        }
    } else {
        oldLeader.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("你当前不在一个队伍里!").aqua()])])
    }
    return 1
}

/**@type {Internal.Map<String,Party>}*/
const partyList = Utils.newMap()
/**@type {Internal.Map<String,Internal.List<PartyInvitation>}*/
const UnprocessedPartyInvitation = Utils.newMap()

/**
 * @param {Internal.Player} Player
*/
function creatNewParty(Player) {
    var party = new Party(Player)
    partyList.put(Player.username, party)
    return party
}

/**
 * @param {String} name
 * @returns {Party}
*/
function getPartyByLeaderName(name) {
    if (partyList.containsKey(name)) {
        return partyList.get(name)
    } else {
        return false
    }
}


function getPlayerByName(name) {
    var players = Utils.server.players
    for (const index in players) {
        if (players[index].username == name) {
            return players[index]
        }
    }
}


/**
 * @param {Internal.Player} Player
*/

function Party(Player) {
    /**@type {String}*/
    this.leader = Player.username
    /**@type {Internal.List<String>}*/
    this.member = Utils.newList()
    Player.forgePersistentData.putString("isInParty", this.leader)
}
/**
 * @param {Internal.Player} Player
*/

Party.prototype.addNewMember = function (Player) {
    Player.forgePersistentData.putString("isInParty", this.leader)
    this.member.add(Player.username)
}
/**
 * @param {Internal.Player} Player
*/
Party.prototype.removeMember = function (Player) {
    var iterator = this.member.iterator()
    while (iterator.hasNext()) {
        var memberName = iterator.next()
        if (memberName == Player.username) {
            iterator.remove()
            Player.forgePersistentData.remove("isInParty")
            break
        }
    }
}

Party.prototype.getAllMember = function () {
    /**@type {Internal.List<Internal.Player>}*/
    var allMember = Utils.newList()
    this.member.forEach((name) => {
        allMember.add(getPlayerByName(name))
    })
    allMember.add(getPlayerByName(this.leader))

    return allMember
}



/**
 * @param {Internal.Player} inviter
*/
function PartyInvitation(inviter) {
    this.inviterName = inviter.username
    this.remainingTime = 60 * 20
}
PartyInvitation.prototype.update = function () {
    this.remainingTime--
}

/**
 * @param {Internal.Player} inviter
 * @param {Internal.Player} Player
*/
function addNewPartyInvitation(Player, inviter) {
    if (!UnprocessedPartyInvitation.containsKey(Player.username)) {
        UnprocessedPartyInvitation.put(Player.username, Utils.newList())
    }
    UnprocessedPartyInvitation.get(Player.username).add(0, new PartyInvitation(inviter))
}

ServerEvents.tick(event => {
    UnprocessedPartyInvitation.forEach((_, Array) => {
        var iterator = Array.iterator()
        while (iterator.hasNext()) {
            var partyInvitation = iterator.next()
            partyInvitation.update()
            if (partyInvitation.remainingTime <= 0) {
                iterator.remove()
            }
        }
    })
})


if (Utils.server) {
    Utils.server.players.forEach(Player => {
        if (Player.forgePersistentData.contains("isInParty") && Player.forgePersistentData.getString("isInParty") == Player.username) {
            Player.forgePersistentData.putString("isInParty", Player.username)
            creatNewParty(Player)
        }
    })


    Utils.server.players.forEach(Player => {
        if (Player.forgePersistentData.contains("isInParty") && Player.forgePersistentData.getString("isInParty") != Player.username) {
            var party = getPartyByLeaderName(Player.forgePersistentData.getString("isInParty"))
            if (party) {
                party.addNewMember(Player)
            }
        }
    })
}

PlayerEvents.loggedIn(event => {
    if (event.player.forgePersistentData.contains("isInParty")) {
        event.player.forgePersistentData.remove("isInParty")
    }
})

PlayerEvents.loggedOut(event => {
    if (event.player.forgePersistentData.contains("isInParty")) {
        var party = getPartyByLeaderName(event.player.forgePersistentData.getString("isInParty"))
        if (party) {
            party.getAllMember().forEach(Player => {
                if (Player != event.player) {
                    Player.tell([Component.join([Component.ofString("[party] ").bold().blue(), Component.ofString("由于 " + event.player.username + " 已离线,自动将其移出了队伍").aqua()])])
                }
            })
            event.player.runCommandSilent("/party leave")
        }
    }
})